package physgin;

import javax.media.j3d.*;
import javax.vecmath.*;
import javax.vecmath.Point3f;
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.image.*;
import java.awt.Container;

/**
 * Describes the additional structures of a Body in a world
 * displayed with the J3D graphics library.
 */
public class J3dBody extends Body<BranchGroup>
    {
        private Point3f old_pos;
        private float old_angle;
        
        private BranchGroup objRoot;
        private TransformGroup objTrans;
        private Primitive shape;
        
        /**
         * Default constructor.
         * Builds a Body suitable for displaying in a J3D world, using the parameters
         * to describe its initial structure.
         *
         * @param   f   String specifying the file to use as the objets texture.
         * @param   s   Shapes indicating the shape of the Body.
         * @param   fs  Variable length list of arguments for Body parameters
         * @see         Body
         */
        public J3dBody(String f, Shapes s, float... fs)
        {
            super(s, fs);
            
            float si = this.getPhys().getSize();
            
            Appearance ap = new Appearance();
            
            Color3f ambientColor  = new Color3f(.5f, .5f, .5f);
            Color3f emissiveColor = new Color3f(0.0f, 0.0f, 0.0f);
            Color3f diffuseColor  = new Color3f(.5f, .5f, .5f);
            Color3f specularColor = new Color3f(0.0f, 0.0f, 0.0f);
            ap.setMaterial(new Material(ambientColor, emissiveColor, diffuseColor, specularColor, 1f));
            
            Texture texture;
            texture = J3dWorld.TextureCache.loadResource(f);
            
            TextureAttributes texAttr = new TextureAttributes();
            texAttr.setTextureMode(TextureAttributes.COMBINE);
            ap.setTexture(texture);
            ap.setTextureAttributes(texAttr);
            
            int ps = Primitive.GENERATE_TEXTURE_COORDS;
            
            switch (s)
            {
                case CIRCLE:
                    shape = new Sphere(si, ps, ap);
                    break;
                case SQUARE:
                    shape = new Box(si, si, si, ps, ap);
                    break;
            }
            
            createSceneGraph();
        }
        
        private void createSceneGraph()
        {
            Point3f p;
            float a;
            
            a = this.orientation();
            p = this.position();
            objRoot = new BranchGroup();
            objTrans = new TransformGroup();
            
            objRoot.setCapability(Group.ALLOW_CHILDREN_WRITE);
            objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
            
            Transform3D initialPos = new Transform3D();
            initialPos.setTranslation(new Vector3d(p.x,p.y,p.z));
            initialPos.setRotation(new AxisAngle4d(0f, 0f, p.z, a));
            objTrans.setTransform(initialPos);
            
            old_pos = p;
            old_angle = a;
            
            objTrans.addChild(shape);
            objRoot.addChild(objTrans);
        }
        
        /**
         * Returns the Body as a BranchGroup for displaying in a J3D library
         * based world. 
         *
         * @return  BranchGroup representation of the Body
         * @see     javax.media.j3d.BranchGroup
         */
        BranchGroup getObject()
        {
            return objRoot;
        }
        
        /**
         * Updates the graphical representations of the Body obects position in
         * the visual display. 
         *
         * @return  void
         */
        void update()
        {
            Point3f p;
            float angle;
            
            updatePos();
            p = position();
            angle = orientation();
            
            Transform3D trans = new Transform3D();
            
            trans.setTranslation(new Vector3d(p.x, p.y, p.z));
            trans.setRotation(new AxisAngle4d(0f, 0f, p.z, angle));
            
            old_pos = p;
            old_angle = angle;
            
            objTrans.setTransform(trans);
        }
    }
